package utils

import(
	"bytes"
	"crypto/tls"
	"encoding/json"
	"net/http"
	"net"
	"time"
	"github.com/astaxie/beego/logs"
	"io/ioutil"
	"context"
	"sync"
	"fmt"
	"errors"
)

func HttpPost(postUrl string, contentType string, SmsPostBody interface{}) (map[string]interface{}, error){
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(SmsPostBody)
	var tr *http.Transport
	//设置 client 的 TLS 信息， 超时时间
	tr = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          100,
		IdleConnTimeout:       90 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Post(postUrl, contentType, b)
	if err != nil {
		logs.Error(err.Error())
		return nil, err
	}
	defer resp.Body.Close()
	var result map[string]interface{}
	//byte
	body,err := ioutil.ReadAll(resp.Body)
	json.Unmarshal(body, &result)
	if err == nil {
		logs.Info(result)
		return result, err
	} else {
		logs.Error(err)
		return result, err
	}
}

func HttpGet(getUrl string) (map[string]interface{}, error){
	var tr *http.Transport	
	//设置 client 的 TLS 信息， 超时时间
	tr = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          100,
		IdleConnTimeout:       90 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get(getUrl)
	if err != nil {
		logs.Error(err.Error())
		return nil, err
	}
	defer resp.Body.Close()
	var result map[string]interface{}
	body,err := ioutil.ReadAll(resp.Body)
	json.Unmarshal(body, &result)
	if err == nil {
		logs.Info(result)
		return result, err
	} else {
		logs.Error(err)
		return nil, err
	}
}

type respData struct {
    resp *http.Response
    err  error
}


func HttpGetWithContext(ctx context.Context, url string, params interface{}) (map[string]interface{}, error){
    var wg sync.WaitGroup
    wg.Add(1)
    defer wg.Wait()
	//通道，返回请求结果
	respChan := make(chan *respData, 1)
	//启动一个goroutine,执行匿名函数，http请求
    go func() {
		// goroutine结束就登记-1
		defer wg.Done()
		var tr *http.Transport
		tr = &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
		client := &http.Client{Transport: tr}
		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			logs.Error("new requestg failed, err:%v\n", err)
			return
    	}
		req = req.WithContext(ctx)
        resp, err := client.Do(req)
        fmt.Printf("client.do resp:%v, err:%v\n", resp, err)
        rd := &respData{
            resp: resp,
            err:  err,
        }
		//将请求结果回写到通道
        respChan <- rd
    }()
    select {
		case <-ctx.Done():
			//transport.CancelRequest(req)
			return nil, errors.New("http call timeout")
		case result := <-respChan:
			fmt.Println("call server api success")
			if result.err != nil {
				fmt.Printf("call server api failed, err:%v\n", result.err)
				return nil, result.err
			}
			defer result.resp.Body.Close()
			data, _ := ioutil.ReadAll(result.resp.Body)
			logs.Info("resp:%v\n", string(data))
			//存放返回数据
			var respdata map[string]interface{}
			err := json.Unmarshal(data, &respdata)
			if err == nil {
				logs.Info(respdata)
				return respdata, err
			} else {
				logs.Error(err)
				return nil, err
			}
    }
}